#include <stdio.h>
#include <string.h>
#if 0
#include "adaptor.h"
#include "dm_interface.h"
#include "bcmConfig.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#endif
#include "aodo.h"

int portmappingmodifyflag = 0;
int l3forwardingmodifyflag = 0;

FILE *tr_fopen( const char *name, const char *mode )
{
	char fn[FILE_PATH_LEN];

	snprintf(fn, FILE_PATH_LEN, "%s%s", TR69C_STORE_PATH, name);
	return fopen( fn, mode );
}

void tr_fclose( FILE *fp )
{
	fclose( fp );
}

int tr69c_read_mapfile(char* filename, mapInfo_t* mapInfos, int num)
{
	int i = 0;
	char szinstance[16];
	char value[MAXMAPLEN];
	int  instance;
	
	FILE* fp = tr_fopen(filename,"r");
	
	if (fp)
	{
		while(!feof(fp))
		{
			memset(szinstance,0,16);
			memset(value,0,MAXMAPLEN);
			fscanf(fp,"%s %*s %s",szinstance,value);\
			printf("mapfile instance %s : value %s\n", szinstance,value);
			instance  = atoi(szinstance);
			if (instance > 0)
			{
				mapInfos[i].valid = 1;
				mapInfos[i].instance = instance;
				strcpy(mapInfos[i].value, value);
				i++;
			}
		}
		tr_fclose(fp);

		return 0;
	}
	else
	{
		return -1;
	}
}

int tr69c_save_mapfile(char* filename, mapInfo_t* mapInfos, int num)
{
	int i;
	/* save mapping info */
	FILE* fp = tr_fopen(filename,"w");
	if (fp)
	{
		for(i=0;i<num;i++)
		{
			if (mapInfos[i].valid)
			{
				printf("tr69c_save_mapfile 1: %d = %s\n",mapInfos[i].instance,mapInfos[i].value);
				fprintf(fp,"%d = %s\n",mapInfos[i].instance,mapInfos[i].value);
			}
		}
		
		tr_fclose(fp);
		return 0;
	}

	return -1;
}

int tr69c_update_mapfile(char * mapfilename,char *value, int inst)
{
	int i = 0;
	mapInfo_t mapInfos[MAXMAPITEMS];
	
	memset(mapInfos,0,sizeof(mapInfo_t)*MAXMAPITEMS);
	tr69c_read_mapfile(mapfilename,mapInfos,MAXMAPITEMS);

	/* update */
	for(i=0;i<MAXMAPITEMS;i++)
	{
		if (mapInfos[i].instance == inst)
		{
			strcpy(mapInfos[i].value, value);
			break;
		}
	}
	
	tr69c_save_mapfile(mapfilename,mapInfos,MAXMAPITEMS);
		
	return 0;
}

int tr69c_map_exist_in_kva(mapInfo_t *mapInfo, char (*kva)[][MAXMAPLEN], int number)
{
	int exist = 0;
	int j = 0;

	exist = 0;
	if (mapInfo->valid)
	{
		for(j=0;j<number;j++)
		{
			if (strcmp((*kva)[j],mapInfo->value) == 0)
			{
				exist = 1;
				break;
			}
		}
	}
		
	return exist;
}

int tr69c_kv_exist_in_map(char *kv, mapInfo_t (*mapInfo)[MAXMAPITEMS], int number)
{
	int exist = 0;
	int j = 0;

	exist = 0;
	for(j=0; j<number; j++)
	{
		if ((*mapInfo)[j].valid)
		{
			if (strcmp((*mapInfo)[j].value, kv) == 0)
			{
				exist = 1;
				break;
			}
		}
	}
		
	return exist;
}

void tr69c_insert_kv_to_map(mapInfo_t (*mapInfos)[MAXMAPITEMS], char *kv, int in)
{
	int j = 0;
	
	for(j=0; j<MAXMAPITEMS; j++)
	{
		if (!(*mapInfos)[j].valid)
		{
			(*mapInfos)[j].valid = 1;
			(*mapInfos)[j].instance = in;
			strcpy((*mapInfos)[j].value, kv);
			break;
		}
	}
}

int tr69c_getvalue_mapfile_byinstance(char* filename,char *value, int inst)
{
	int i = 0;
	int instance;
	char szinstance[16];
	char szvalue[MAXMAPLEN];
	
	FILE *fp = tr_fopen(filename,"r");
	if (fp)
	{
		/* need add get mapping info from mapping file */
		while(!feof(fp))
		{
			fscanf(fp,"%s %*s %s",szinstance,szvalue);
			instance	= atoi(szinstance);
			if (instance == inst)
			{
				/* get value by elinkname*/
				printf("value = %s \n", szvalue);
				strcpy(value,szvalue);
				tr_fclose(fp);
				return 0;
			}
			i++;
		}
		tr_fclose(fp);
	}
		
	return -1;
}

int tr69c_update_readonly_children(char* path,char* key,char keyvalue[][MAXMAPLEN],int number,char* mapfilename)
{
	mapInfo_t mapInfos[MAXMAPITEMS];
	int i = 0;

	if ((path == NULL) || (key == NULL))
	{
		return -1;
	}

#if 0
	/* delete all instance object */
	memset(mapInfos,0,sizeof(mapInfo_t)*MAXMAPITEMS);
	tr69c_read_mapfile(mapfilename,mapInfos,MAXMAPITEMS); 
	for(i=0;i<MAXMAPITEMS;i++)
	{
		if (mapInfos[i].valid)
		{
				// todo node tree do 
				//tr69c_delObjInstance(objectpath, mapInfos[i].instance, mapInfos[i].instance);
		}
	}

	/* if instance number > node->il, you can set node il value in tr.xml */
	memset(mapInfos,0,sizeof(mapInfo_t)*MAXMAPITEMS);
	printf("tr69c_init_readonly_children number %d \n", number);
	int res;
	for (i=0;i<number;i++)
	{
		res = tr69c_ao( node, node->nin, NULL ); //add object
		if (res == 0)
		{
			char paraname[128];
			node_t target;
			
			sprintf(paraname,"%s%d.%s", path,node->nin,key);
			printf("paraname: %s \n", paraname);
			if (tr69c_resolve_node(paraname,&target) == 0) //find node of 'paraname'
			{
				mapInfos[i].valid = 1; //always
				mapInfos[i].instance = node->nin; //save to mapping tree
				strcpy(mapInfos[i].value, keyvalue[i]);
			}
			else
			{
				printf("lib resolve_node failed : %s", paraname);
			}
		}
	}

	tr69c_save_mapfile(mapfilename,mapInfos,MAXMAPITEMS);
#endif
	return 0;
}

int tr69c_update_writeable_children(char* path,char* key,char keyvalue[][MAXMAPLEN],int number,char* mapfilename)
{
	mapInfo_t mapInfos[MAXMAPITEMS];
	int i,j;
	char exsit;
	int instance;
	int in = 0;
	char objectpath[256];
	
	strcpy(objectpath,path);

	if ((path == NULL) || (key == NULL))
	{
		return -1;
	}
	
	memset(mapInfos, 0, sizeof(mapInfo_t)*MAXMAPITEMS);
	tr69c_read_mapfile(mapfilename, mapInfos, MAXMAPITEMS); 

	/* delete mapping file info which not in real links */
	for(i=0;i<MAXMAPITEMS;i++)
	{
		if (mapInfos[i].valid)
		{
			printf("+++++++++++++++%s: %s, %d",path, mapInfos[i].value, mapInfos[i].instance);
			if (!tr69c_map_exist_in_kva(&mapInfos[i], keyvalue, number))
			{
				mapInfos[i].valid = 0;
				// todo node tree do 
				//tr69c_delObjInstance(objectpath, mapInfos[i].instance, mapInfos[i].instance);
			}
		}
	}

	/*delete instance object from tree which not in mapping file */

	/*delete mapping file items which not in node tree */

	/* if instance number > node->il, you can set node il value in tr.xml */
	
	/* add others real links not in mapping file */
	for(i=0; i<number; i++)
	{
		if (!tr69c_kv_exist_in_map(keyvalue[i], mapInfos, MAXMAPITEMS))
		{
			// todo node tree add object
			//int in = add_object(objectpath,strlen(objectpath));
			//if ( in > 0)
			{
				//tr69c_insert_kv_to_map(mapInfos, keyvalue[i], in);
				tr69c_insert_kv_to_map(mapInfos, keyvalue[i], i);
				tr69c_save_mapfile(mapfilename, mapInfos, MAXMAPITEMS);
			}
		}
	}
	
	return 0;
}

#if 0
// ------------------ tagt init ------------------------
int tr69c_init_PortMapping_children(node_t node)
{
	char keyvalue[MAXMAPITEMS][MAXMAPLEN];
	int  number = 0;
	int  ret = 0;
	printf(  "path: %s", "tr69c_init_PortMapping_children" );
	
	number = get_PortMapping_InternalPort(keyvalue);
	printf("################################################number[%d]",number);
	printf("################################################keyvalue[%s]",keyvalue[0]);
	portmappingmodifyflag = 1;
	ret = tr69c_init_writeable_children(node,"Device.NAT.PortMapping.","ExternalPort",keyvalue,number,PortMappingMap);
	portmappingmodifyflag = 0;
	return ret;
}

// ------------------ tagt rpc ao ------------------------

int tr69c_add_portmapping_entry()
{
	int i = 0;
	int ret = -1;
	char num_val[16] = {0};
	char secname[64] = {0};
	char linebuf[512] = {0};
	char tmparray[128] = {0};
	char index[16] = {0};

	ret = do_uci_get(NET_FW_PORTFWD_MAXINDEX, num_val);

	sprintf(tmparray,"pf%d", atoi(num_val)+1);
	sprintf(linebuf, "firewall_nat.%s", tmparray);
	do_uci_set(linebuf, "port_fwd");
	printf("linebuf [%s]",linebuf);

	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.port_range", tmparray);
	do_uci_set(linebuf, "0");
	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.local_port", tmparray);
	do_uci_set(linebuf, "0");
	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.srv_name", tmparray);
	do_uci_set(linebuf, "None");
	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.local_ip", tmparray);
	do_uci_set(linebuf, "0.0.0.0");
	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.protocol", tmparray);
	do_uci_set(linebuf, "0");
	memset(linebuf, 0, sizeof(linebuf));

	sprintf(linebuf, "firewall_nat.%s.index", tmparray);
	sprintf(index, "%d", atoi(num_val)+1);
	do_uci_set(linebuf, index);
	
	memset(linebuf, 0, sizeof(linebuf));
	sprintf(linebuf, "firewall_nat.%s.is_enable", tmparray);
	do_uci_set(linebuf, "0");

	sprintf(tmparray,"%d", atoi(num_val)+1);
	do_uci_set(NET_FW_PORTFWD_MAXINDEX, tmparray);

	do_uci_get(NET_FW_PORTFWD_NUM, num_val);
	sprintf(tmparray,"%d", atoi(num_val)+1);
	do_uci_set(NET_FW_PORTFWD_NUM, tmparray);

}

int tr69c_add_portmapping_object(node_t node, uint32_t instance)
{
	char buff[8192] = {0};
	FILE *fp = NULL;
	char *p = NULL;
	char *q = NULL;
	char *s = NULL;
	char entry[32][1024] = {0};
	int i = 0;
	int j = 0;
	char isenable[32] = {0};
	
	mapInfo_t mapInfos[MAXMAPITEMS];
	printf("tr69c_add_portmapping_object 1: %s",node->name);
	memset(mapInfos,0,sizeof(mapInfo_t)*MAXMAPITEMS);
	tr69c_read_mapfile(PortMappingMap,mapInfos,MAXMAPITEMS); 

	char paraname[128];
	node_t target;

	for(i=0,j=0;i<MAXMAPITEMS;i++)
	{
		if (mapInfos[i].valid == 1)
		{
			j++;
		}
	}

	if (j >= node->il){
		printf("Number is larger than node->il");
		return -1;
	}

	for(i=0;i<MAXMAPITEMS;i++)
	{
		if (mapInfos[i].valid == 0)
		{
			mapInfos[i].valid = 1;

			mapInfos[i].instance = instance;

			strcpy(mapInfos[i].value,"0"); //tmp value 
			tr69c_add_portmapping_entry();
			break;
		}
	}

	tr69c_save_mapfile(PortMappingMap,mapInfos,MAXMAPITEMS);	
	
	sprintf(paraname,"Device.NAT.PortMapping.%d.ExternalPort", instance);
	if (tr69c_resolve_node(paraname,&target) == 0)
	{
		tr69c_set_value(target,"0"); //tmp value
	}

	return 0;
}



// ------------------ tagt rpc do ------------------------

int tr69c_del_portmapping_entry(char *ExternalPort)
{
	int i = 0;
	int ret = -1;
	char linebuf[128] = {0};
	char tmparray[64] = {0};
	char valbuf[64] = {0};
	char *ptr = NULL;

	printf("set ExternalPort [%s]",ExternalPort);

	for(i=0; i<MAX_PF_ELEM; i++)
	{
		sprintf(tmparray, "firewall_nat.pf%d", i);
		sprintf(linebuf, "%s.port_range", tmparray);
		printf("linebuf [%s]",linebuf);
		ret = do_uci_get(linebuf, valbuf);
		if (ret != 0)
		{
			continue;
		}
		ptr = strchr(valbuf, ':');
		if(ptr != NULL)
		{
			*ptr = '\0';
		}
		if(strcmp(valbuf, ExternalPort) == 0)
		{
			do_uci_delete(tmparray,NULL);	
			break;
		}
	}

	/*fp = fopen("/etc/portforwarding_save.txt", "r");
	if(fp != NULL)
	{
		fgets(buff, sizeof(buff), fp);
		s = buff;
		printf("s: %s\n", s);

		p = strstr(buff, "IsEnable");
		if(p != NULL)
		{
			q = strchr(p, ',');
			if(q != NULL)
				strncpy(isenable, p-1, q- (p-1));

			printf("isenable: %s\n", isenable);
			
		}
		
		while((p = strstr(s, "ServiceName")) != NULL)
		{
			if((q = strchr(p, '}')) != NULL)
			{
				strncpy(entry[i], p-2, (q+1) - (p-2));
				i++;
				s = q + 1;
			}
		}
		fclose(fp);
	}
	
	sprintf(buff, "{%s,\"PortForwardList\":[", isenable);
	printf("buff: %s\n", buff);

	char portrage[1024] = {0};
	int tmpflag = 0;
	
	for(j=0; j<i; j++)
	{
		if((p = strstr(entry[j], "PortRange")) != NULL)
		{
			q = strchr(p, ':');
			s = strchr(p, ',');
			if(q != NULL && s != NULL)
			{
				memset(portrage, 0, sizeof(portrage));
				strncpy(portrage, q+2, (s-1)-(q+2));
				printf("portrage: %s\n", portrage);
			}
		}

		if ((p = strstr(portrage, ":")) != NULL)
			*p = '\0';

		if(strcmp(portrage, ExternalPort) == 0)
		{
			continue;
		}
		printf("entry[j]: %s\n", entry[j]);
		strcat(buff, entry[j]);
		strcat(buff, ",");
		tmpflag++;
	}
	if(tmpflag != 0)
	{
		p = strrchr(buff, ',');
		if(p != NULL)
		{
			*p = '\0';
		}
	}
 	strcat(buff, "]}");

	fp = fopen("/etc/portforwarding_save.txt", "w");
	if(fp != NULL)
	{
		fputs(buff, fp);
		fclose(fp);
	}*/
}


int tr69c_del_portmapping_object(node_t node)
{
	mapInfo_t mapInfos[MAXMAPITEMS];
	int i,j;
	char ExternalPort[128];
	int instance;

	memset(mapInfos,0,sizeof(mapInfo_t)*MAXMAPITEMS);
	tr69c_read_mapfile(PortMappingMap,mapInfos,MAXMAPITEMS); 
	
	
	char paraname[128];
	node_t target;
	
	instance = atoi(node->name);
	printf("tr69c_del_portmapping_object : node->name :%s\n",node->name);
	node_t child;

	memset(ExternalPort,0,sizeof(ExternalPort));
	for( ; node->children; ) 
	{
		child = node->children;
		node->children = child->brother;

		if (strcmp(child->name, "ExternalPort") == 0)
		{
			strcpy(ExternalPort,child->value);
			break;
		}
		
	}
	printf("ExternalPort :%s\n", ExternalPort);
	for(i=0;i<MAXMAPITEMS;i++)
	{
		if ((mapInfos[i].valid) && (mapInfos[i].instance == instance) 
		&& (strcmp(mapInfos[i].value,ExternalPort) == 0))
		{
			mapInfos[i].valid = 0;
			tr69c_del_portmapping_entry(ExternalPort);
		}
	}
	
	tr69c_save_mapfile(PortMappingMap,mapInfos,MAXMAPITEMS);

	return 0;
}
#endif

#ifdef L3FORWARDING

#define BUFF_MAX_LEN 2048
#define MAX_STATIC_ROUTE_IPV4 15


static int TW_split_rules(char *rule, char **szRule, char *szDelimit)
{
	char *p_result = NULL;
	int i = 0;
	
	if(NULL == rule || NULL == szRule || /* NULL == strstr(rule, szDelimit) */ NULL == szDelimit)
	{
		return -1;
	}
	
	p_result = strtok( rule, szDelimit );

	while(NULL != p_result)
	{
		//printf("p_result=%s\n", p_result);
		*(szRule+i) = p_result;
		p_result = strtok( NULL, szDelimit );
		i++;
	}

	return i;
}

#if 1
int tr69c_get_L3Forwarding_Name(char names[][MAXMAPLEN])
{
	char *pEnabled = NULL, *pName = NULL, *pIPAddress = NULL, *pNetMask = NULL;
	char *pGateway = NULL, *pMetric = NULL, *pInterface = NULL;
	char TokenName[32];
	char *pTokenValue=NULL;
	char TokenValue[1024] = {0};
	int n = 0, i = 0, num = 0;
	char *pSplitValues[10] = {NULL};
	char l3f[MAX_STATIC_ROUTE_IPV4][128]={
		"1;192.168.100.0;255.255.255.0;192.168.9.1;5;WAN;sr1",
		"1;192.168.199.0;255.255.255.0;192.168.9.1;5;WAN;sr2",
		";;;;;;",
		";;;;;;",
		";;;;;;",";;;;;;",";;;;;;",";;;;;;",";;;;;;",
		";;;;;;",";;;;;;",";;;;;;",";;;;;;",";;;;;;",
		";;;;;;"};

	for (i=0 ; i<MAX_STATIC_ROUTE_IPV4 ; i++)
		{
			snprintf(TokenName, sizeof(TokenName), "StaticRouteIPv4_%d", i);
			// Get token value		
			//pTokenValue = nvram_safe_get(TokenName);
			pTokenValue = l3f[i];
			sprintf(TokenValue, "%s", pTokenValue);
			printf("i = %d, TokenValue=%s\n", i, TokenValue);
			if (strcmp(pTokenValue, "")==0 || strcmp(pTokenValue, ";;;;;;")==0)
				break;
			// Splite token value
			TW_split_rules(TokenValue, pSplitValues, ";");			
			pEnabled = pSplitValues[0];
			if (pEnabled==NULL || strcmp(pEnabled, "")==0)
				break;			
			pIPAddress = pSplitValues[1];
			pNetMask = pSplitValues[2];  
			pGateway = pSplitValues[3];  
			pMetric = pSplitValues[4];  
			pInterface = pSplitValues[5];
			pName = pSplitValues[6]; //TODO: by EAP if Name contains ";", parsing will fail. FIX ME
			printf("pEnabled=%s, pIPAddress=%s, pNetMask=%s, pGateway=%s, pMetric=%s, pInterface=%s, pName=%s\n", 
				pEnabled, pIPAddress, pNetMask, pGateway, pMetric, pInterface, pName);
			strcpy(names[num], pName);
			num++;
		}

	return num;
}
#endif

int tr69c_update_L3Forwarding_children(char *path)
{
	char keyvalue[MAXMAPITEMS][MAXMAPLEN];
	//char keyvalue[MAXMAPITEMS][MAXMAPLEN] = {"one", "two", "three", "four", "five"};
	int  number = 5;
	int ret = 0;
	
	number = tr69c_get_L3Forwarding_Name(keyvalue);
	l3forwardingmodifyflag = 1;
	ret = tr69c_update_writeable_children(path,"name",keyvalue,number,L3ForwardingMap);
	l3forwardingmodifyflag = 0;
	
	return ret;
}

#endif
// ------------------ web ao ------------------------


// ------------------ web do ------------------------

void tr69c_mio_init()
{
	//tr69c_update_PortMapping_children(PORTMAPPING_PATH);
	tr69c_update_L3Forwarding_children(L3FORWARDING_PATH);
}

void tr69c_mio_update(char *path)
{
	if (path)
	{
		if (strcmp(path,PORTMAPPING_PATH) == 0)
		{
			//tr69c_update_PortMapping_children(path);
		}
		else if (strcmp(path,L3FORWARDING_PATH) == 0)
 		{
			tr69c_update_L3Forwarding_children(path);
		}
	}
}

/*
void tr69c_mio_add_object(char *path)
{
	printf("%s path:%s\n", __FUNCTION__, path);

	if (path)
	{
		printf("Do tr69c_ao_commit: path=%s, instance=%d\n", path, instance);
		if (strcmp(path,PORTMAPPING_PATH) == 0)
		{
			printf("tr69c_add_portmapping_object entry\n");
			if(portmappingmodifyflag == 0)
				tr69c_add_portmapping_object(path, instance);
		}
		else if (strcmp(path,L3FORWARDING_PATH) == 0)
		{
			printf("tr69c_add_l3forwarding_object l3forwardingmodifyflag: %d\n", l3forwardingmodifyflag);
			if(l3forwardingmodifyflag == 0)
				tr69c_add_l3forwarding_object(path, instance);
		}
	}
}

void tr69c_mio_del_object(char *path)
{
	printf("%s path:%s\n", __FUNCTION__, path);

	if (path)
	{
		if (strcmp(path,PORTMAPPING_PATH) == 0)
		{
			printf("tr69c_del_portmapping_object entry\n");
			tr69c_del_portmapping_object(path);
		}
		else if (strcmp(path,L3FORWARDING_PATH) == 0)
		{
			printf("tr69c_del_l3forwarding_object entry\n");
			tr69c_del_l3forwarding_object(path);
		}
	}
}
*/

void main()
{
	tr69c_mio_init();
}
